package com.study.crypto.signer;

import com.study.crypto.utils.KeyUtils;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;

/**
 * @author Songjin
 * @since 2021-01-03 12:22
 */
public abstract class Signer {
    
    public static final String BC = BouncyCastleProvider.PROVIDER_NAME;
    public static final byte[] SM2_ID                 = "1234567812345678".getBytes();
    public static final String SIGN_ALGO_SHA256_RSA   = "SHA256WithRSA";
    public static final String SIGN_ALGO_SHA256_ECDSA = "SHA256WithECDSA";
    public static final String SIGN_ALGO_SM3_SM2      = "SM3WithSM2";
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 使用私钥对原文签名
     * @param inData     原文
     * @param privateKey 私钥
     * @return 签名值
     * @throws IOException 异常
     * @throws CryptoException 异常
     * @throws GeneralSecurityException 异常
     * @throws CMSException 异常
     */
    public abstract byte[] sign(byte[] inData, PrivateKey privateKey) throws IOException, CryptoException, GeneralSecurityException, CMSException;
    
    /**
     * 验签
     * @param inData    签名数据
     * @param signature 签名值
     * @param publicKey 公钥
     * @return 验签通过 | 未通过
     * @throws GeneralSecurityException 异常
     */
    public abstract boolean verify(byte[] inData, byte[] signature, PublicKey publicKey) throws GeneralSecurityException;
    
    /**
     * 验签
     * @param inData        签名数据
     * @param signature     签名值
     * @param certificate   公钥证书
     * @return 验签通过 | 未通过
     * @throws IOException 异常
     * @throws GeneralSecurityException 异常
     */
    public boolean verify(byte[] inData, byte[] signature, Certificate certificate) throws IOException, GeneralSecurityException {
        SubjectPublicKeyInfo publicKeyInfo = certificate.getSubjectPublicKeyInfo();
        PublicKey publicKey = KeyUtils.obtainPublicKey(publicKeyInfo);
        return this.verify(inData, signature, publicKey);
    }
}
